package io.adrainty.bolee.trade.handler;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import io.adrainty.bolee.framework.commons.basic.EnableEnum;
import io.adrainty.bolee.framework.commons.basic.ResponseCode;
import io.adrainty.bolee.framework.commons.exception.AppException;
import io.adrainty.bolee.trade.models.entity.PayChannelEntity;
import io.adrainty.bolee.trade.models.entity.TradeEntity;
import io.adrainty.bolee.trade.models.valobj.PayChannelEnum;
import io.adrainty.bolee.trade.models.valobj.TradeStatusEnum;
import io.adrainty.bolee.trade.repository.IPayChannelRepository;
import io.adrainty.bolee.trade.repository.ITradeRepository;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;

/**
 * @author AdRainty
 * @version V1.0.0
 * @since 2025/8/31 下午11:26
 */

public abstract class AbstractPayHandler implements IPayHandler {

    @Resource
    protected ITradeRepository tradeRepository;

    @Resource
    protected IdentifierGenerator identifierGenerator;

    @Resource
    protected IPayChannelRepository payChannelRepository;

    @Override
    public TradeEntity wapTrade(TradeEntity tradeVO) {
        checkBeforeCreateTrade(tradeVO);
        PayChannelEntity payChannel = getPayChannel();
        return doWapTrade(tradeVO, payChannel);
    }

    @Override
    public TradeEntity closeTrade(TradeEntity tradeVO) {
        TradeEntity tradeEntity = checkBeforeCloseTrade(tradeVO);
        PayChannelEntity payChannel = getPayChannel();
        doCloseTrade(tradeEntity.getTradeOrderNo(), payChannel);
        tradeEntity.setTradeState(TradeStatusEnum.CLOSED);
        tradeRepository.updateTradeById(tradeEntity);
        return tradeEntity;
    }

    @Override
    public TradeEntity h5SignContract(TradeEntity tradeVO) {
        return null;
    }

    /**
     * 关闭交易
     *
     * @param tradeOrderNo 交易参数
     * @param payChannel   支付渠道配置
     */
    protected abstract void doCloseTrade(Long tradeOrderNo, PayChannelEntity payChannel);

    /**
     * 创建交易
     *
     * @param tradeVO    交易参数
     * @param payChannel 支付渠道配置
     * @return 交易单
     */
    protected abstract TradeEntity doWapTrade(TradeEntity tradeVO, PayChannelEntity payChannel);

    protected PayChannelEntity getPayChannel() {
        PayChannelEntity param = PayChannelEntity.builder()
                .channelLabel(supportPayChannel().getCode())
                .dataState(EnableEnum.ENABLE)
                .build();
        return payChannelRepository.findOne(param);
    }

    /**
     * 检查创建交易参数
     *
     * @param tradeVO 交易参数
     */
    private void checkBeforeCreateTrade(TradeEntity tradeVO) {
        if (tradeVO == null) throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        if (StringUtils.isAnyBlank(tradeVO.getTradeChannel(), tradeVO.getCompanyNo())) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        if (ObjectUtils.anyNull(tradeVO.getProductOrderNo(), tradeVO.getTradeAmount())) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        if (PayChannelEnum.WECHAT_PAY.getCode().equals(tradeVO.getTradeChannel()) && StringUtils.isBlank(tradeVO.getOpenId())) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }

        TradeEntity tradeEntity = tradeRepository.findTradByProductOrderNo(tradeVO.getProductOrderNo());
        // 交易单为空：之前未对此订单做过支付
        if (tradeEntity == null) {
            tradeVO.setTradeOrderNo((Long) identifierGenerator.nextId(tradeVO));
            return;
        }

        // 交易单不为空：判定交易单状态
        switch (tradeEntity.getTradeState()) {
            case PAYED, WAIT_PAY -> throw new AppException(ResponseCode.TRADE_STATE_ERROR);
            case CLOSED -> tradeVO.setTradeOrderNo((Long) identifierGenerator.nextId(tradeVO));
        }

    }

    /**
     * 检查关闭交易参数
     *
     * @param tradeVO 订单参数
     * @return 交易单
     */
    private TradeEntity checkBeforeCloseTrade(TradeEntity tradeVO) {
        if (tradeVO == null) throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        if (Objects.isNull(tradeVO.getTradeOrderNo())) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }
        TradeEntity tradeEntity = tradeRepository.findTradByProductOrderNo(tradeVO.getProductOrderNo());
        if (tradeEntity == null) {
            throw new AppException(ResponseCode.TRADE_NOT_EXIST);
        }
        return tradeEntity;
    }

}
